package com.xu.service;

import com.github.pagehelper.PageInfo;
import com.xu.mapper.UserCourseMapper;
import com.xu.pojo.Course;
import com.xu.pojo.CourseDto;
import com.xu.quartz.QuartzConfig;
import com.xu.utils.DateUtil;
import com.xu.utils.RedisLock;
import com.xu.utils.RedisUtil;
import org.quartz.SchedulerException;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
@EnableScheduling
public class SelectServiceImpl implements SelectService {

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private RedisLock redisLock;

    @Autowired
    private QuartzConfig quartzConfig;

    @Autowired
    private UserCourseMapper userCourseMapper;

    @Autowired
    RabbitTemplate rabbitTemplate;


    private static final int TIMOUT = 100;


    @Override
    public String setSelectTime(Date startTime, Date endTime){

        boolean isSet = redisUtil.hasKey("start_time");
        if (redisUtil.hasKey("start_time") && (int)redisUtil.get("select_state")==1){
            return "选课已开始，无法修改";
        }
        else{
            long startTimeStamp = startTime.getTime();
            long endTimeStamp = endTime.getTime();

            if (startTimeStamp>=endTimeStamp || DateUtil.compareCurrentDate(startTimeStamp-1000*60))
                return "选课开始时间和结束时间设置错误";
            else{
                redisUtil.set("start_time",startTimeStamp);
                redisUtil.set("end_time",endTimeStamp);
                redisUtil.set("select_state",0);
                userCourseMapper.delallUserCourse();
                Date preTime = new Date(startTimeStamp - 1000*60);
                try{
                    if (isSet){
                        quartzConfig.modifyJob("PreSelectJob","group1",DateUtil.getCron(preTime));
                        quartzConfig.modifyJob("StartSelectJob","group1",DateUtil.getCron(startTime));
                        quartzConfig.modifyJob("EndSelectJob","group1",DateUtil.getCron(endTime));

                    }
                    else
                        quartzConfig.startJob(DateUtil.getCron(preTime),DateUtil.getCron(startTime),DateUtil.getCron(endTime));
                } catch (SchedulerException e) {
                    e.printStackTrace();
                    return "选课时间设置失败";
                }


                return "选课时间设置成功";
            }
        }
    }



    @Override
    public long[] getSeSelectTime() {
        if (redisUtil.hasKey("start_time")){
            long a1[]=new long[2];
            a1[0] = (long)redisUtil.get("start_time");
            a1[1] = (long)redisUtil.get("end_time");
            return a1;
        }
        else
            return null;
    }


    @Override
    public boolean isPrepareCourse() {
        if (redisUtil.hasKey("start_time")){
            long startTimeStamp = (long)redisUtil.get("start_time");
            return DateUtil.compareCurrentDate(startTimeStamp - 1000 * 60);
        }
        else
            return false;
    }

    @Override
    public int getStock(int courseId) {
        Integer courseStock = (Integer) redisUtil.hget("course_stock", Integer.toString(courseId));
        return courseStock;
    }

    @Override
    public List<Course> SetStock(List<Course> courses) {
        //如果选课开始，则用redis中的stock数据覆盖
        Integer selectState = (Integer)redisUtil.get("select_state");
        if (selectState!=null && selectState ==1){
            for (Course course:courses){
                Integer course_stock = (Integer) redisUtil.hget("course_stock", Integer.toString(course.getCourseId()));
                course.setStock(course_stock);
            }
        }
        return courses;
    }


    @Override
    public PageInfo<Course> SetStock(PageInfo<Course> courses) {
        //如果选课开始，则用redis中的stock数据覆盖
        Integer selectState = (Integer)redisUtil.get("select_state");
        if (selectState!=null && selectState ==1){
            for (Course course:courses.getList()){
                Integer course_stock = (Integer) redisUtil.hget("course_stock", Integer.toString(course.getCourseId()));
                course.setStock(course_stock);
            }
        }
        return courses;
    }

    @Override
    public long getremainSeconds() {
        Long startTime = (Long)redisUtil.get("start_time");
        if (startTime!=null){
            Date date = new Date();
            long currentTimeStamp = date.getTime();
            return (startTime -currentTimeStamp)/1000;
        }
        else
            return -1;
    }


    @Override
    public int getSelectState() {
        Integer selectState = (Integer)redisUtil.get("select_state");
        if (selectState==null)
            return -1;
        else
            return selectState;
    }

    @Override
    public String selectCourse(int userId, int courseId) {

        Integer selectState = (Integer)redisUtil.get("select_state");
        if (selectState==null || selectState ==0)
            return "选课未开始";
        if ( selectState == 2)
            return "选课已结束";

        if (redisUtil.sHasKey(userId+"_course",Integer.toString(courseId)))
            return "该课程已选择，请勿重复选择";

        //加锁，查询课程余量并减一
        long time = System.currentTimeMillis() + TIMOUT;
        if (!redisLock.lock(courseId+"_lock", String.valueOf(time))) {
            return "选课失败，请再次尝试";
        }
        boolean result;
        Integer stock = (Integer)redisUtil.hget("course_stock",Integer.toString(courseId));
        if (stock<=0)
            result = false;
        else{
            redisUtil.hset("course_stock",Integer.toString(courseId), stock - 1);
            redisUtil.sSet(userId+"_course",Integer.toString(courseId));

            //压入消息队列
            Map<String,Object> map=new HashMap<>();
            map.put("method","add");
            map.put("userId",Integer.toString(userId));
            map.put("courseId",Integer.toString(courseId));
            rabbitTemplate.convertAndSend("DirectExchange", "DirectRouting", map);

            result = true;
        }
        redisLock.unlock(courseId+"_lock", String.valueOf(time));

        if (result){

            return "选课成功";
        }
        else
            return "选课失败，课程人数达到上限";

    }

    @Override
    public String dropCourse(int userId, int courseId) {
        Integer selectState = (Integer)redisUtil.get("select_state");
        if (selectState==null || selectState ==0)
            return "选课未开始";
        if ( selectState == 2)
            return "选课已结束";

        if (!redisUtil.sHasKey(userId+"_course",Integer.toString(courseId)))
            return "该课程已删除，请勿重复删除";

        //加锁
        long time = System.currentTimeMillis() + TIMOUT;
        if (!redisLock.lock(courseId+"_lock", String.valueOf(time))) {
            return "退课失败，请再次尝试";
        }

        Integer stock = (Integer)redisUtil.hget("course_stock",Integer.toString(courseId));
        redisUtil.hset("course_stock",Integer.toString(courseId), stock + 1);
        redisUtil.setRemove(userId+"_course",Integer.toString(courseId));

        //压入消息队列
        Map<String,Object> map=new HashMap<>();
        map.put("method","delete");
        map.put("userId",Integer.toString(userId));
        map.put("courseId",Integer.toString(courseId));
        rabbitTemplate.convertAndSend("DirectExchange", "DirectRouting", map);

        redisLock.unlock(courseId+"_lock", String.valueOf(time));

        return "退课成功";


    }

    @Override
    public List<Course> getUserCourse(int userId) {
        if (redisUtil.hasKey("select_state")){
            Set<Object> courseIds = redisUtil.sGet(userId + "_course");
            if (courseIds!=null) {
                List<Course> courses = new ArrayList<>();
                for (Object courseId : courseIds) {
                    CourseDto courseDto = (CourseDto) redisUtil.hget("course_info",(String) courseId);
                    courses.add(new Course(courseDto, Integer.valueOf((String) courseId).intValue() ));
                }
                return courses;
            }
            else
                return null;
        }
        return userCourseMapper.querySelectCourse(userId);
    }
}
